package com.tanhua.dubbo.server.api;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.dubbo.config.annotation.Service;
import com.tanhua.dubbo.server.pojo.UserLike;
import com.tanhua.dubbo.server.vo.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Service(version = "1.0.0")
@Slf4j
public class UserLikeApiImpl implements UserLikeApi{


    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    public static final String LIKE_REDIS_KEY_PREFIX = "USER_LIKE_";

    public static final String NOT_LIKE_REDIS_KEY_PREFIX = "USER_NOT_LIKE_";

    @Override
    public Boolean likeUser(Long userId, Long likeUserId) {
       if(this.isLike(userId,likeUserId)){
           return false;
       }

        UserLike userLike = new UserLike();
        userLike.setId(ObjectId.get());
        userLike.setUserId(userId);
        userLike.setLikeUserId(likeUserId);
        userLike.setCreated(System.currentTimeMillis());
        //保存到数据库
        this.mongoTemplate.save(userLike);
        //保存到redis
        String redisKey = this.getLikeRedisKey(userId);
        String hashKey = String.valueOf(likeUserId);
        this.redisTemplate.opsForHash().put(redisKey,hashKey,"1");

        //判断喜欢的人 之前是否存在在不喜欢列表中  将其移出
        if(this.isNotLike(userId,likeUserId)){
            redisKey = this.getNotLikeRedisKey(userId);
            this.redisTemplate.opsForHash().delete(redisKey,hashKey);
        }

        return true;

    }

    /**
     * 获取喜欢数据的redis key
     *
     * @param userId
     * @return
     */
    private String getLikeRedisKey(Long userId){
        return LIKE_REDIS_KEY_PREFIX + userId;
    }

    /**
     * 获取不喜欢数据的redis key
     *
     * @param userId
     * @return
     */
    private String getNotLikeRedisKey(Long userId){
        return NOT_LIKE_REDIS_KEY_PREFIX + userId;
    }

    /**
     * 是否喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean isLike(Long userId, Long likeUserId){
        String redisKey = this.getLikeRedisKey(userId);
        String hashKey = String.valueOf(likeUserId);
        return this.redisTemplate.opsForHash().hasKey(redisKey, hashKey);
    }

    /**
     * 是否不喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    private Boolean isNotLike(Long userId, Long likeUserId){
        String redisKey = this.getNotLikeRedisKey(userId);
        String hashKey = String.valueOf(likeUserId);
        return this.redisTemplate.opsForHash().hasKey(redisKey, hashKey);
    }

    @Override
    public Boolean notLikeUser(Long userId, Long likeUserId) {
        if(this.isNotLike(userId, likeUserId)){
            return false;
        }

        String redisKey = this.getNotLikeRedisKey(userId);
        String hashKey = String.valueOf(likeUserId);
        this.redisTemplate.opsForHash().put(redisKey,hashKey,"1");

        //判断该用户是否之前存在在喜欢人的列表中  将其删除
        if(this.isLike(userId, likeUserId)){
            Query query = Query.query(Criteria.where("userId").is(userId)
                        .and("likeUserId").is(likeUserId));
            this.mongoTemplate.remove(query,UserLike.class);

            redisKey = this.getLikeRedisKey(userId);
            this.redisTemplate.opsForHash().delete(redisKey,hashKey);
        }
        return true;

    }

    @Override
    public Boolean isMutualLike(Long userId, Long likeUserId) {
        return this.isLike(userId, likeUserId) && this.isLike(likeUserId,userId);
    }

    @Override
    public List<Long> queryLikeList(Long userId) {
        String redisKey = this.getLikeRedisKey(userId);
        Set<Object> keys = this.redisTemplate.opsForHash().keys(redisKey);
        if(ObjectUtil.isEmpty(keys)){
            return ListUtil.empty();
        }

        List<Long> result = new ArrayList<>(keys.size());
        keys.forEach(o -> result.add(Convert.toLong(o)));

        return result;
    }

    @Override
    public List<Long> queryNotLikeList(Long userId) {
        String redisKey = this.getNotLikeRedisKey(userId);
        Set<Object> keys = this.redisTemplate.opsForHash().keys(redisKey);
        if(ObjectUtil.isEmpty(keys)){
            return ListUtil.empty();
        }

        List<Long> result = new ArrayList<>(keys.size());
        keys.forEach(o -> result.add(Convert.toLong(o)));

        return result;
    }

    @Override
    public Long queryMutualLikeCount(Long userId) {
        List<Long> list = this.queryLikeList(userId);
        Long count = 0L;
        for (Long likeUserId : list) {
            String likeRedisKey = this.getLikeRedisKey(likeUserId);
            String hashKey = String.valueOf(userId);
            if(this.redisTemplate.opsForHash().hasKey(likeRedisKey,hashKey)){
                count ++;
            }
        }

        return count;
    }

    @Override
    public Long queryLikeCount(Long userId) {
        String RedisKey = this.getLikeRedisKey(userId);
        return this.redisTemplate.opsForHash().size(RedisKey);
    }

    @Override
    public Long queryFanCount(Long userId) {
      Query query = Query.query(Criteria.where("likeUserId").is(userId));
      return this.mongoTemplate.count(query,UserLike.class);
    }

    @Override
    public PageInfo<UserLike> queryMutualLikeList(Long userId, Integer page, Integer pageSize) {
        List<Long> list = this.queryLikeList(userId);
        Query query = Query.query(Criteria.where("userId").in(list)
                    .and("likeUserId").is(userId));
        return this.queryList(query,page,pageSize);
    }

    @Override
    public PageInfo<UserLike> queryLikeList(Long userId, Integer page, Integer pageSize) {
      Query query = Query.query(Criteria.where("userId").is(userId));
      return this.queryList(query,page,pageSize);
    }

    @Override
    public PageInfo<UserLike> queryFanList(Long userId, Integer page, Integer pageSize) {
        Query query = Query.query(Criteria.where("likeUserId").is(userId));
        return this.queryList(query,page,pageSize);
    }

    private PageInfo<UserLike> queryList(Query query,Integer page,Integer pageSize){
        PageRequest pageRequest = PageRequest.of(page-1,pageSize,
                Sort.by(Sort.Order.desc("created")));
        query.with(pageRequest);

        List<UserLike> userLikes = this.mongoTemplate.find(query, UserLike.class);
        PageInfo<UserLike> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setRecords(userLikes);

        return pageInfo;

    }
}
